package fr.noe.amicaleloisirs.concours.view;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Cursor;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.ui.CaptionPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;

import fr.noe.amicaleloisirs.concours.business.Player;
import fr.noe.amicaleloisirs.concours.interfaces.CallbackHandler;
import fr.noe.amicaleloisirs.concours.interfaces.CallbackUpdatePlayer;
import fr.noe.amicaleloisirs.concours.utils.Constants;
import fr.noe.amicaleloisirs.concours.utils.XMLHelper;
import gwtquery.plugins.draggable.client.DraggableOptions;
import gwtquery.plugins.draggable.client.DraggableOptions.RevertOption;
import gwtquery.plugins.draggable.client.events.DragStartEvent;
import gwtquery.plugins.draggable.client.events.DragStartEvent.DragStartEventHandler;
import gwtquery.plugins.draggable.client.gwt.DraggableWidget;

import static com.google.gwt.query.client.GQuery.$;

/**
 * 
 * @author Sébastien PREVOST
 *
 */
public class ListeJoueursPanel extends CaptionPanel {

	private FlexTable flexTable;
	private List<Player> players = new ArrayList<Player>();
	private DraggableOptions draggableOptions;

	private int NEW_PLAYER = -1;

	public ListeJoueursPanel() {
		super("Liste des joueurs");
		getElement().setId(Constants.LISTE_JOUEURS_ELEMENT_ID);
		
		setWidth("100%");

		flexTable = new FlexTable();
		setContentWidget(flexTable);
		flexTable.getColumnFormatter().setWidth(0, "200px");
		flexTable.getColumnFormatter().setWidth(1, "200px");
		flexTable.setWidth("100%");

		flexTable.setText(0, 0, "Prénom");
		flexTable.setText(0, 1, "Nom");
		flexTable.getRowFormatter().addStyleName(0, "gridHeader");
		
		initDragOperation();
	}

	public void updatePlayer(Player p, int index) {
		// index 0 => header, commence à 1, mais à 0 dans la liste
		players.remove(index - 1);
		players.add(index - 1, p);
		addPlayer(p.getFirstname(), p.getLastname(), index);
	}

	public void addPlayers(List<Player> list) {
		for (Player p : list) {
			addPlayer(p);
		}
	}

	public void addPlayer(Player p) {
		players.add(p);
		addPlayer(p.getFirstname(), p.getLastname(), NEW_PLAYER);
	}
	
	public Player getPlayerByIndex(int index) {
		if (index > -1) {
			return players.get(index);
		}
		return null;
	}

	private void addPlayer(String prenom, String nom, int id) {
		final int index = id >= 0 ? id : flexTable.getRowCount();
		Label prenomLabel = new Label(prenom);
		Label nomLabel = new Label(nom);

		MouseOverHandler mohSelect = new MouseOverHandler() {
			public void onMouseOver(MouseOverEvent event) {
				flexTable.getRowFormatter().addStyleName(index, "selected");
			}
		};
		MouseOutHandler mohUnselect = new MouseOutHandler() {
			public void onMouseOut(MouseOutEvent event) {
				flexTable.getRowFormatter().removeStyleName(index, "selected");
			}
		};
		ClickHandler clickHandler = new ClickHandler() {
			public void onClick(ClickEvent event) {
				CallbackUpdatePlayer callback = new CallbackUpdatePlayer() {
					@Override
					public void onValidate(final Player p) {
						new ConfirmPopUp("Mise à jour du joueur "
								+ p.getFirstname() + " " + p.getLastname()
								+ " ?", new CallbackHandler() {
							@Override
							public void onValidate() {
								XMLHelper.get().updatePlayer(p);
								updatePlayer(p, index);
							}

							@Override
							public void onCancel() {
								// Do nothing
							}
						});
					}

					@Override
					public void onCancel(final Player p) {
						// Do nothing
					}
				};
				flexTable.getRowFormatter().removeStyleName(index, "selected");

				// index 0 => header, commence à 1, mais à 0 dans la liste
				new CreatePlayerView("Modifier le joueur", players
						.get(index - 1), callback);
			}
		};

		prenomLabel.addMouseOverHandler(mohSelect);
		prenomLabel.addMouseOutHandler(mohUnselect);
		prenomLabel.addClickHandler(clickHandler);
		nomLabel.addMouseOverHandler(mohSelect);
		nomLabel.addMouseOutHandler(mohUnselect);
		nomLabel.addClickHandler(clickHandler);

		DraggableWidget<Label> draggablePrenomLabel = new DraggableWidget<Label>(
				prenomLabel, draggableOptions);
		DraggableWidget<Label> draggableNomLabel = new DraggableWidget<Label>(
				nomLabel, draggableOptions);

		DragStartEventHandler dragStartHandler = new DragStartEventHandler() {

			@Override
			public void onDragStart(DragStartEvent event) {
				Element helper = event.getHelper();
				SafeHtmlBuilder sb = new SafeHtmlBuilder();
				// reuse the contact cell to render the inner html of the drag
				// helper.
				render (players.get(index - 1), sb);
				helper.setInnerHTML(sb.toSafeHtml().asString());
				
				// set attribut avec l'index du joueur pour récupérer lors du drop
				helper.setAttribute(Constants.ATTRIBUTE_PLAYER_INDEX, (index - 1) + "");
			}

		};

		draggableNomLabel.addDragStartHandler(dragStartHandler);
		draggablePrenomLabel.addDragStartHandler(dragStartHandler);

		flexTable.setWidget(index, 0, draggablePrenomLabel);
		flexTable.setWidget(index, 1, draggableNomLabel);
		flexTable.getRowFormatter().addStyleName(index, "gridRow");
		if ((index % 2) == 0) {
			flexTable.getRowFormatter().addStyleName(index, "pair");
		} else {
			flexTable.getRowFormatter().addStyleName(index, "impair");
		}
	}

	private void initDragOperation() {

		// retrieve draggableOptions on the column
		DraggableOptions draggableOptions = new DraggableOptions();;
		// use template to construct the helper. The content of the div will be
		// set
		// after
		draggableOptions.setHelper($(Templates.INSTANCE.outerHelper()
				.asString()));
		// opacity of the helper
		draggableOptions.setOpacity((float) 0.8);
		// cursor to use during the drag operation
		draggableOptions.setCursor(Cursor.POINTER);
		// set the revert option
		draggableOptions.setRevert(RevertOption.ON_INVALID_DROP);
		// prevents dragging when user click on the category drop-down list
		draggableOptions.setCancel("select");
		// attach the helper to the document because datagrid is scrollable
		draggableOptions.setAppendTo("body");
		
		this.draggableOptions = draggableOptions;
	}

	static interface Templates extends SafeHtmlTemplates {
		Templates INSTANCE = GWT.create(Templates.class);

		@Template("<div id='dragHelper' align='center' style='border:1px solid black; background-color:#ffffff; color:black; width:240px; margin:0 auto;'></div>")
		SafeHtml outerHelper();
	}

	public void render(Player p, SafeHtmlBuilder sb) {
		// Value can be null, so do a null check..
		if (p == null) {
			return;
		}
		sb.appendEscaped(p.getFirstname());
		sb.appendHtmlConstant(" ");
		sb.appendEscaped(p.getLastname());
	}

}